package com.easylinkin.linkappapi.schedule.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.easylinkin.bases.redis.util.RedisUtil;
import com.easylinkin.linkappapi.schedule.service.JobCallService;
import com.easylinkin.linkappapi.shigongyun.entity.JkMonitorInfo;
import com.easylinkin.linkappapi.shigongyun.entity.JkMonitorRecord;
import com.easylinkin.linkappapi.shigongyun.mapper.JkMonitorInfoMapper;
import com.easylinkin.linkappapi.shigongyun.mapper.JkMonitorRecordMapper;
import com.easylinkin.linkappapi.shigongyun.vo.MonitorInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;

/**
 * @author zhengwen
 **/
@Slf4j
@Service
public class JobCallServiceImpl implements JobCallService {


    @Autowired
    private RedisUtil redisUtil;

    @Resource
    private JkMonitorInfoMapper monitorInfoMapper;

    @Resource
    private JkMonitorRecordMapper monitorRecordMapper;


    /**
     * redisKey基坑监测模块缓存前缀
     */
    private final static String redisKeyBase = "siteMonitor:";

    @Override
    public RestMessage jkMonitorDataConverSave(MonitorInfoVo monitorInfoVo) {
        Date now = DateUtil.date();
        String tenantId = monitorInfoVo.getTenantId();

        String monitorDataUrl = monitorInfoVo.getMonitorDataUrl();
        String key = redisKeyBase + "config:monitorData:url";
        if (StringUtils.isBlank(monitorDataUrl)) {
            Object monitorPointTypeUrlObj = redisUtil.get("key");
            if (monitorPointTypeUrlObj != null) {
                monitorDataUrl = monitorPointTypeUrlObj.toString();
            } else {
                monitorDataUrl = "http://111.47.25.55:50030/oauth/wkProjectItem/getMonitorDataByProjectId3?projectId=";
            }
        } else {
            redisUtil.set(key, monitorDataUrl);
        }
        //参数校验,是否校验Url合法性？
        Assert.isTrue(StringUtils.isNotBlank(monitorDataUrl), "获取基坑监测数据url为空");

        String projectId = monitorInfoVo.getProjectId();
        Assert.isTrue(StringUtils.isNotBlank(projectId), "基坑所属项目ID为空");
        monitorDataUrl += projectId;
        String dataStr = HttpUtil.get(monitorDataUrl);
        if (JSONUtil.isJson(dataStr)) {
            JSONObject jsonObj = JSONUtil.parseObj(dataStr);
            JkMonitorInfo jkMonitorInfo = new JkMonitorInfo();
            //1基坑监测数据
            jkMonitorInfo.setDataType("1");
            jkMonitorInfo.setCollectTime(DateUtil.format(now, DatePattern.NORM_DATETIME_MINUTE_FORMAT));
            jkMonitorInfo.setProjectId(projectId);
            jkMonitorInfo.setTenantId(tenantId);
            jkMonitorInfo.setCreateTime(now);
            int inNum = monitorInfoMapper.insert(jkMonitorInfo);
            if (inNum == 1) {
                //转换监测数据保存
                converMonitorDataSave(jkMonitorInfo, jsonObj.getStr("data"));
            }
            return RestBuilders.successBuilder().data(null).build();
        }
        return RestBuilders.failureBuilder().message("获取基坑监测数据为空").build();
    }

    @Override
    public RestMessage jkMonitorDataConfigTrans(MonitorInfoVo monitorInfoVo) {

        updateMonitorPoint(monitorInfoVo);

        Date now = monitorInfoVo.getAutoTime();
        if (now == null) {
            now = DateUtil.date();
        }
        String tenantId = monitorInfoVo.getTenantId();

        String monitorDataUrl = monitorInfoVo.getMonitorDataUrl();

        String projectId = monitorInfoVo.getProjectId();

        monitorDataUrl += projectId;
        String dataStr = null;
        log.info("-----获取基坑检测数据URL：{}",monitorDataUrl);
        if (monitorInfoVo.getTimeOut() != null) {
            dataStr = HttpUtil.get(monitorDataUrl,monitorInfoVo.getTimeOut());
        }else{
            dataStr = HttpUtil.get(monitorDataUrl);
        }
        if (JSONUtil.isJson(dataStr)) {
            log.info("---第三方基坑检测数据获取返回：{}",dataStr);
            JSONObject jsonObj = JSONUtil.parseObj(dataStr);
            JkMonitorInfo jkMonitorInfo = new JkMonitorInfo();
            //1基坑监测数据
            jkMonitorInfo.setDataType("1");
            jkMonitorInfo.setCollectTime(DateUtil.format(now, DatePattern.NORM_DATETIME_MINUTE_FORMAT));
            jkMonitorInfo.setProjectId(projectId);
            jkMonitorInfo.setTenantId(tenantId);
            jkMonitorInfo.setCreateTime(now);
            int inNum = monitorInfoMapper.insert(jkMonitorInfo);
            if (inNum == 1) {
                //转换监测数据保存
                converMonitorDataSave(jkMonitorInfo, jsonObj.getStr("data"));
            }
            return RestBuilders.successBuilder().data(null).build();
        }else{
            log.error("---第三方基坑检测数据获取返回异常：{}",dataStr);
        }
        return RestBuilders.failureBuilder().message("获取基坑监测数据为空").build();
    }

    private void updateMonitorPoint(MonitorInfoVo monitorInfoVo) {
        String tenantId = monitorInfoVo.getTenantId();
        String monitorPointTypeUrl = monitorInfoVo.getMonitorPointTypeUrl();

        String projectId = monitorInfoVo.getProjectId();
        String monitorPointTypeDataUrl = monitorPointTypeUrl + projectId;
        String dataStr = null;
        log.info("-----更新基坑分类URL：{}",monitorPointTypeDataUrl);
        if(monitorInfoVo.getTimeOut() != null){
            dataStr = HttpUtil.get(monitorPointTypeDataUrl,monitorInfoVo.getTimeOut());
        }else{
            dataStr = HttpUtil.get(monitorPointTypeDataUrl);
        }
        if (JSONUtil.isJson(dataStr)) {
            String monitorPointTypeResDataKey = redisKeyBase + "monitorPointType:resData:" + tenantId;
            JSONObject dataJson = JSONUtil.parseObj(dataStr);
            String resData = dataJson.getStr("data");
            if (StringUtils.isNotBlank(resData)) {
                redisUtil.set(monitorPointTypeResDataKey, resData);
            }
        }
    }

    /**
     * 转换监测数据保存
     *
     * @param jkMonitorInfo 监测数据主记录
     * @param dataStr       监测数据
     */
    private void converMonitorDataSave(JkMonitorInfo jkMonitorInfo, String dataStr) {
        if (jkMonitorInfo != null && JSONUtil.isJsonArray(dataStr)) {
            JSONArray dataArray = JSONUtil.parseArray(dataStr);
            if (CollectionUtil.isNotEmpty(dataArray)) {
                dataArray.stream().forEach(c -> {
                    JSONObject jc = JSONUtil.parseObj(c);
                    JkMonitorRecord monitorRecord = converMonitorRecord(jkMonitorInfo, jc, null);
                    int inNum = monitorRecordMapper.insert(monitorRecord);
                    if (inNum == 1) {
                        JSONArray childrenJsonArr = jc.getJSONArray("children");
                        childrenJsonArr.stream().forEach(d -> {
                            JSONObject jd = JSONUtil.parseObj(d);
                            JkMonitorRecord childMonitorRecord = converMonitorRecord(jkMonitorInfo, jd,
                                    monitorRecord.getId());
                            monitorRecordMapper.insert(childMonitorRecord);
                        });
                    }
                });
            }
        }
    }

    /**
     * 监测数据记录转换
     *
     * @param jkMonitorInfo 监测数据主记录
     * @param dataJson      监测数据
     * @param parentId      监测数据父级id
     * @return 监测数据记录
     */
    private JkMonitorRecord converMonitorRecord(JkMonitorInfo jkMonitorInfo, JSONObject dataJson,
                                                Long parentId) {
        JkMonitorRecord jkMonitorRecord = new JkMonitorRecord();
        jkMonitorRecord.setInfoId(jkMonitorInfo.getId());
        jkMonitorRecord.setWarningLevel(dataJson.getInt("warningLevel"));
        jkMonitorRecord.setMeasurementProjectName(dataJson.getStr("measurementProjectName"));
        Date createTime = dataJson.getDate("createTime");
        if (createTime==null){
            createTime = new Date();
        }
        jkMonitorRecord.setCreateTime(createTime);
        jkMonitorRecord.setAlarmValue(dataJson.getStr("alarmValue"));
        jkMonitorRecord.setProjectId(jkMonitorInfo.getProjectId());
        jkMonitorRecord.setTotalChangeResult(dataJson.getStr("totalChangeResult"));
        jkMonitorRecord.setPointName(dataJson.getStr("pointName"));
        boolean isMaximum = dataJson.getBool("isMaximum");
        jkMonitorRecord.setIsMaximum(isMaximum);
        BigDecimal percent = BigDecimal.ZERO;
        if (!dataJson.getStr("percent").equals("NaN")) {
            try {
                percent = dataJson.getBigDecimal("percent");
            }catch (Exception e){
                percent = BigDecimal.ZERO;
            }

        }
        jkMonitorRecord.setPercent(NumberUtil.toStr(percent));
        jkMonitorRecord.setSourceId(dataJson.getStr("id"));
        jkMonitorRecord.setChangeRate("0");
        jkMonitorRecord.setSingleChangeResult("0");

        JSONObject points = dataJson.getJSONObject("points");
        log.info(JSONUtil.toJsonStr(points));
        //jkMonitorRecord.setPoints();
        jkMonitorRecord.setStorageTime(DateUtil.date());

        if (parentId != null) {
            jkMonitorRecord.setParentId(parentId);
        }
        //数据处理（2列要自己计算的，依赖之前的数据，迭代 + 缓存处理算了）
        calculateAndCacheData(jkMonitorRecord);
        return jkMonitorRecord;
    }

    /**
     * 计算并缓存数据（计算自定义的数据）
     *
     * @param monitorRecord 数据源
     */
    private void calculateAndCacheData(JkMonitorRecord monitorRecord) {
        String projectId = monitorRecord.getProjectId();
        String pointName = monitorRecord.getPointName();
        Date curCurrentTime = monitorRecord.getCreateTime();
        BigDecimal curTcr = BigDecimal.ZERO;
        String tcr = monitorRecord.getTotalChangeResult();
        if (StringUtils.isNotBlank(tcr)) {
            try {
                curTcr = new BigDecimal(tcr);
            }catch (Exception e){
                curTcr = BigDecimal.ZERO;
            }

        }

        JSONObject lastTcrData = new JSONObject();
        lastTcrData.set("totalChangeResult", curTcr);
        lastTcrData.set("createTime", curCurrentTime);

        String lastPointNameTcrKey = redisKeyBase + projectId + ":" + pointName + ":totalChangeResult";

        Object pointNameValObj = redisUtil.get(lastPointNameTcrKey);
        if (pointNameValObj != null) {
            lastTcrData = JSONUtil.parseObj(pointNameValObj.toString());
            BigDecimal lastTcr = lastTcrData.getBigDecimal("totalChangeResult");
            if (lastTcr != null) {
                Date lastCreateTime = lastTcrData.getDate("createTime");
                long btMinutes = DateUtil.between(lastCreateTime, curCurrentTime, DateUnit.MINUTE, true);
                BigDecimal hom = BigDecimal.valueOf(NumberUtil.mul(NumberUtil.div(btMinutes, 60, 8), 24));
                if (!lastCreateTime.equals(curCurrentTime)) {
                    //数据时间变化，认为数据变化
                    //计算单次变化量
                    double singleCr = NumberUtil.sub(curTcr.doubleValue(), lastTcr.doubleValue());
                    monitorRecord.setSingleChangeResult(NumberUtil.toStr(singleCr));
                    //计算变化速率
                    if (hom.doubleValue() > 0d) {
                        BigDecimal changeRate = NumberUtil.div(singleCr, hom, 6);
                        monitorRecord.setChangeRate(NumberUtil.toStr(changeRate));
                    }

                }

            } else {
                lastTcrData.set("totalChangeResult", curTcr);
                lastTcrData.set("createTime", curCurrentTime);
            }

        }
        redisUtil.set(lastPointNameTcrKey, lastTcrData);

    }


}
